package com.alibaba.citrus.ots.sales.plan.facade.service.statistics;

import com.alibaba.citrus.ots.common.annotation.FacadeInvoker;
import com.alibaba.citrus.ots.common.exception.FacadeException;
import com.alibaba.citrus.ots.common.util.CalculatePercentage;
import com.alibaba.citrus.ots.sales.plan.api.salesplan.SalesPlanQueryService;
import com.alibaba.citrus.ots.sales.plan.api.statistics.SalesPlanScItemStatWriteService;
import com.alibaba.citrus.ots.sales.plan.dto.api.request.DeleteSalesPlanScItemStatRequest;
import com.alibaba.citrus.ots.sales.plan.dto.api.request.QueryPlanScItemStatRequest;
import com.alibaba.citrus.ots.sales.plan.dto.api.request.QuerySalesPlanRequest;
import com.alibaba.citrus.ots.sales.plan.dto.api.response.GoodsOwnershipDepartmentResponse;
import com.alibaba.citrus.ots.sales.plan.facade.service.salesplan.publish.SharePie;
import com.alibaba.citrus.ots.sales.plan.functions.ability.model.DeletePlanScItemAbilityRequest;
import com.alibaba.citrus.ots.sales.plan.functions.salesplan.SalesPlanLineEntity;
import com.alibaba.citrus.ots.sales.plan.functions.salesplan.SalesPlanScItemStatEntity;
import com.alibaba.citrus.ots.sales.plan.functions.salesplan.SalesPlanStatAbility;
import com.alibaba.citrus.ots.sales.plan.repository.SalesPlanLineRepository;
import com.alibaba.citrus.ots.sales.plan.repository.SalesPlanScItemStatRepository;
import com.alibaba.citrus.ots.sales.plan.sdo.SalesPlanLineSDO;
import com.alibaba.citrus.ots.sales.plan.sdo.SalesPlanSDO;
import com.alibaba.citrus.ots.sales.plan.sdo.SalesPlanStatScItemSDO;
import com.alibaba.lattice2.epoch.sdk.model.Result;
import com.epoch.app.bcots.model.dto.PlanScItemLoadListRequest;
import com.epoch.app.bcots.model.dto.PlanStatServiceRequest;
import com.epoch.app.bcots.model.dto.PlanStatServiceResponse;
import com.epoch.app.bcots.sales_plan.planscitem.model.PlanScItem;
import com.epoch.app.bcots.sales_plan.planscitem.service.PlanScItemService;
import com.epoch.app.bcots.sales_plan.salesplandetail.dto.LoadSalesPlanDetailListRequest;
import com.epoch.app.bcots.sales_plan.salesplandetail.dto.UpdateSalesPlanDetailResponse;
import com.epoch.app.bcots.sales_plan.salesplandetail.model.SalesPlanDetail;
import com.epoch.app.bcots.sales_plan.salesplandetail.service.SalesPlanDetailService;
import com.epoch.app.bcots.service.SalesPlanService;
import com.google.common.collect.Maps;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author yuhailin
 * @description:
 * @date 2021-09-27 10:38
 */
@Component
public class SalesPlanScItemStatWriteServiceImpl implements SalesPlanScItemStatWriteService {

    @Resource
    private SalesPlanScItemStatRepository salesPlanScItemStatRepository;

    @Resource
    private SalesPlanStatAbility salesPlanStatAbility;

    @Resource
    private SalesPlanDetailService salesPlanDetailService;

    @Resource
    private SalesPlanService salesPlanService;

    @Resource
    private PlanScItemService planScItemService;

    @Resource
    private SalesPlanQueryService salesPlanQueryService;


    @FacadeInvoker
    @Override
    public Result<Boolean> deletePlanScItem(DeleteSalesPlanScItemStatRequest deleteSalesPlanScItemStatRequest) {
        DeletePlanScItemAbilityRequest deletePlanScItemAbilityRequest = new DeletePlanScItemAbilityRequest();
        deletePlanScItemAbilityRequest.setId(deleteSalesPlanScItemStatRequest.getId().toString());
        return Result.success(salesPlanStatAbility.deletePlanScItem(deletePlanScItemAbilityRequest));
    }

    @FacadeInvoker
    @Override
    public Result<Boolean> batchEditPlanScItem(SalesPlanStatScItemSDO salesPlanScItemStatSDO) {
        SalesPlanScItemStatEntity salesPlanScItemStatEntity = SalesPlanScItemStatEntity.of(salesPlanScItemStatSDO);
        return Result.success(salesPlanScItemStatEntity.batchPlanScItemEdit());
    }

    @FacadeInvoker
    @Override
    public Result<Boolean> editSalesPlanScItem(SalesPlanStatScItemSDO salesPlanScItemStatSDO) {
        QueryPlanScItemStatRequest queryPlanScItemStatRequest = new QueryPlanScItemStatRequest();
        queryPlanScItemStatRequest.setId(salesPlanScItemStatSDO.getId().toString());
        SalesPlanStatScItemSDO salesPlanScItem = salesPlanScItemStatRepository.getSalesPlanScItem(queryPlanScItemStatRequest);
        salesPlanScItem.setId(salesPlanScItemStatSDO.getId());
        salesPlanScItem.setTaskCount(salesPlanScItemStatSDO.getTaskCount());
        if (salesPlanScItemStatSDO.getTaskMoney() != null && salesPlanScItemStatSDO.getTaskMoney() != 0) {
            salesPlanScItem.setTaskMoney(salesPlanScItemStatSDO.getTaskMoney());
        }
/*        if (salesPlanScItemStatSDO.getReturnCount() != null && salesPlanScItemStatSDO.getReturnCount() != 0) {
            salesPlanScItem.setReturnCount(salesPlanScItemStatSDO.getReturnCount());
        }*/
        salesPlanScItem.setMonthMiddleTaskCount(salesPlanScItemStatSDO.getMonthMiddleTaskCount());
        salesPlanScItem.setMonthFirstTaskCount(salesPlanScItemStatSDO.getMonthFirstTaskCount());
        salesPlanScItem.setMonthLastTaskCount(salesPlanScItemStatSDO.getMonthLastTaskCount());
        if (salesPlanScItemStatSDO.getMonthFirstCount() != null && salesPlanScItemStatSDO.getMonthFirstCount() != 0) {
            salesPlanScItem.setMonthFirstReturnCount(salesPlanScItemStatSDO.getMonthFirstCount());
            salesPlanScItem.setMonthMiddleReturnCount(salesPlanScItemStatSDO.getMonthMiddleCount());
            salesPlanScItem.setMonthLastReturnCount(salesPlanScItemStatSDO.getMonthLastCount());
        }
        // 构造实体
        SalesPlanScItemStatEntity salesPlanScItemStatEntity = SalesPlanScItemStatEntity.of(salesPlanScItem);
        return Result.success(salesPlanScItemStatEntity.planScItemEdit());
    }


    @Override
    public Result<Boolean> departmentDecomposition(GoodsOwnershipDepartmentResponse departmentResponse) {
        if (StringUtils.isBlank(departmentResponse.getPlanId())) {
            throw new FacadeException("OTS-02-001-00-15-006");
            // return Result.fail(false,,);
        }
        if (StringUtils.isBlank(departmentResponse.getScItemId())) {
            throw new FacadeException("OTS-01-005-02-15-012");
        }
        if (Objects.isNull(departmentResponse.getPoolType())) {
            throw new FacadeException("OTS-02-004-01-15-002");
        }
        if (Objects.isNull(departmentResponse.getMapList())) {
            return Result.success(true);
        }
        //查询出当前货品数据 部门维度有哪些
        Result<List<PlanScItem>> listResult = planScItemService.loadPlanScItemList(PlanScItemLoadListRequest.newPlanScItemLoadListRequestBuilder()
                .planId(departmentResponse.getPlanId())
                .scItemId(departmentResponse.getScItemId())
                .poolType(departmentResponse.getPoolType())
                .bizType(2)
                .build());
        if (CollectionUtils.isEmpty(listResult.getResult())) {
            throw new FacadeException("OTS-05-001-10-16-022");
        }
        //获取当前货品归属于哪些部门  并每个部门分别提报量为多少（monthCount）
        Map<String, Integer> departmentKeyValuePair = listResult.getResult().stream().filter(t -> t.getBizId() != null).collect(Collectors.toMap(PlanScItem::getBizId, PlanScItem::getMonthCount, (k1, k2) -> k1));
        //如果进行修改了某些部门的提报量(month_count)
        //首先获取其是修改哪些部门   获取其中所有的Key
        List<Map<String, Integer>> mapList = departmentResponse.getMapList();

        //根据bizId部门编码 +月度计划ID+货品ID 查找明细列表进行修改MonthCount(提报量)
        LoadSalesPlanDetailListRequest listRequest = new LoadSalesPlanDetailListRequest();
        listRequest.setPlanId(departmentResponse.getPlanId());
        listRequest.setLimit(1000);
        listRequest.setScItemId(departmentResponse.getScItemId());
        //listRequest.setOrgSalesDepartmentCode(orgSalesDepartmentCode);
        Result<List<SalesPlanDetail>> salesPlanDetailList = salesPlanDetailService.loadSalesPlanDetailList(listRequest);
        if (Objects.isNull(salesPlanDetailList)||CollectionUtils.isEmpty(salesPlanDetailList.getResult()) || salesPlanDetailList.getTotal() == 0) {
            throw new FacadeException("OTS-02-004-01-15-043");
        }
        QuerySalesPlanRequest querySalesPlanRequest = new QuerySalesPlanRequest();
        querySalesPlanRequest.setId(departmentResponse.getPlanId());
        Result<SalesPlanSDO> salesPlan = salesPlanQueryService.getSalesPlan(querySalesPlanRequest);
        SalesPlanSDO salesPlanSDO = salesPlan.getResult();
        for (Map<String, Integer> stringIntegerMap : mapList) {
            Set<String> bizIds = stringIntegerMap.keySet();
            for (String orgSalesDepartmentCode : bizIds) {
                //过滤出 明细数据中 跟当前bizId 部门编码一样 并且是当前货品的数据
                List<SalesPlanDetail> decomposeDataList = salesPlanDetailList.getResult().stream().filter(t -> t.getOrgSalesDepartmentCode().equals(orgSalesDepartmentCode) && t.getScItemId().equals(departmentResponse.getScItemId())).collect(Collectors.toList());

                //修改前的提报量
                int beforeModificationCount = decomposeDataList.stream().mapToInt(SalesPlanDetail::getMonthCount).sum();

                //原提报量为0 不参与分解
                if (0==beforeModificationCount){
                    continue;
                }
                //获取当前BizId所对应的value值(修改后的提报量)
                Integer afterModificationCount = stringIntegerMap.get(orgSalesDepartmentCode);

                // 修改前明细提报所占比例
                decomposeDataList.stream().filter(salesPlanDetail -> salesPlanDetail.getMonthCount() != 0).forEach(it -> {
                    BigDecimal rate = new BigDecimal(it.getMonthCount()).divide(new BigDecimal(beforeModificationCount), 2, RoundingMode.DOWN);
                    it.setMonthCount(new BigDecimal(afterModificationCount).multiply(rate).intValue());
                });

                //第一次分配后的剩余数
                int afterFirst = afterModificationCount-decomposeDataList.stream().mapToInt(SalesPlanDetail::getMonthCount).sum();
                if (afterFirst>0){
                    List<SalesPlanDetail> sortedList = decomposeDataList.stream().filter(salesPlanDetail -> salesPlanDetail.getMonthCount() != 0).sorted(Comparator.comparing(SalesPlanDetail::getMonthCount)).collect(Collectors.toList());
                    int size = sortedList.size();

                    if (size>0){

                        for (int i = 0; i < afterFirst; i++) {
                            int index = i % size;
                            sortedList.get(index).setMonthCount(sortedList.get(index).getMonthCount()+1);
                        }
                    }else {
                        int size1 = decomposeDataList.size();
                        for (int i = 0; i < afterFirst; i++) {
                            int index = i % size1;
                            decomposeDataList.get(index).setMonthCount(decomposeDataList.get(index).getMonthCount()+1);
                        }
                    }
                }


              /*  //根据这个部门(所修改的提报量加上之前的量)/原先的量 得到修改的比例 最后进行进行分解到这个货品归属的的部门下
                Integer proportion = (beforeModificationCount + afterModificationCount) / beforeModificationCount;
                //拿最后的结果量去分解给当前所有部门
                Map<String, BigDecimal> map = Maps.newHashMap();
                decomposeDataList.stream().filter(salesPlanDetail -> salesPlanDetail.getMonthCount() != 0).forEach(it -> {
                    //如果当前数据本身就没有提报量 那么就不参与分解
                    //根据数据唯一ID 所对应的那条数据占比最后进行分
                    map.put(it.getId().toString(), new BigDecimal(proportion).multiply(new BigDecimal(it.getMonthCount())));
                });
                SharePie sharePie = new SharePie(map);
                Map<String, BigDecimal> bigDecimalMap = sharePie.share(new BigDecimal(afterModificationCount), 0, RoundingMode.HALF_UP);*/

                //获取分解后每条明细门有都少提报量 准备进行上中下 三旬分解   然后进行落库
                for (SalesPlanDetail it : decomposeDataList) {

                    Integer departmentMonthCount = it.getMonthCount();
                    //for (SalesPlanDetail salesPlanDetail : salesPlanDetailList.getResult()) {
                    //SalesPlanDetail updateSalesPlanDetail = new SalesPlanDetail();
                    //先将原本数据进行拷贝到准备进行修改
                    SalesPlanLineSDO salesPlanLineSDO = new SalesPlanLineSDO();
                    BeanUtils.copyProperties(it, salesPlanLineSDO);
                    //分解的每个部门按照最后分比列
                    salesPlanLineSDO.setMonthCount(departmentMonthCount);
                    //上旬量  比例 3
                    BigDecimal monthFirstProprtion = new BigDecimal(30);
                    BigDecimal firstCount = monthFirstProprtion.multiply(new BigDecimal(Optional.ofNullable(departmentMonthCount).orElse(0)));
                    Integer monthFirstCount = firstCount.divide(new BigDecimal(100)).setScale(0, BigDecimal.ROUND_DOWN).intValue();
                    salesPlanLineSDO.setMonthFirstCount(monthFirstCount);
                    //下旬量  比列 3
                    BigDecimal monthLastProprtion = new BigDecimal(30);
                    BigDecimal LastCount = monthLastProprtion.multiply(new BigDecimal(Optional.ofNullable(departmentMonthCount).orElse(0)));
                    Integer monthLastCount = LastCount.divide(new BigDecimal(100)).setScale(0, BigDecimal.ROUND_DOWN).intValue();
                    salesPlanLineSDO.setMonthLastCount(monthLastCount);
                    //中旬量  剩下的全是中旬的
                    Integer monthMiddleCount = Optional.ofNullable(departmentMonthCount).orElse(0) - (monthFirstCount + monthLastCount);
                    salesPlanLineSDO.setMonthMiddleCount(monthMiddleCount);

                    //计算折前计划金额
                    long costInsuranceFreight = Objects.nonNull(it.getCostInsuranceFreight()) ? it.getCostInsuranceFreight() : 0;
                    long beforeMonthMoney = Optional.ofNullable(departmentMonthCount).orElse(0) * costInsuranceFreight;
                    salesPlanLineSDO.setBeforeMonthMoney(beforeMonthMoney);
                    //计算折后计划金额  折后计划金额=折前计划金额*(1-预估价格折扣率)
                    salesPlanLineSDO.calculateMonthMoney(salesPlanSDO.getEstimateDiscount());
                    //合同差量  合同差量=month_count（计划数量）-month_contract_count（合同量）
                    Integer contractDifferenceCount = Optional.ofNullable(departmentMonthCount).orElse(0) - it.getMonthContractCount();
                    salesPlanLineSDO.setContractDifferenceCount(contractDifferenceCount);
                    //合同差金额 合同差金额=计划折前合同金额 -计划折前金额
                    long contractDifferenceMoney = it.getBeforeMonthContractMoney() - beforeMonthMoney;
                    salesPlanLineSDO.setContractDifferenceMoney(contractDifferenceMoney);
                    //计算折前满足度 折前满足度=折前计划金额/折前合同金额
                    BigDecimal beforeContractSatisfaction = CalculatePercentage.retainTwo(beforeMonthMoney, it.getBeforeMonthContractMoney());
                    salesPlanLineSDO.setBeforeContractSatisfaction(beforeContractSatisfaction);
                    //计算折后满足度  折后满足度 = 折后计划金额/折后合同金额
                    BigDecimal contractSatisfaction = CalculatePercentage.retainTwo(it.getMonthMoney(), it.getMonthContractMoney());
                    salesPlanLineSDO.setContractSatisfaction(contractSatisfaction);
                    //修改滚动量
                    salesPlanLineSDO.setM1RollingPlanCount(Optional.ofNullable(it.getM1RollingPlanCount()).orElse(0));
                    salesPlanLineSDO.setM2RollingPlanCount(Optional.ofNullable(it.getM2RollingPlanCount()).orElse(0));
                    salesPlanLineSDO.setM3RollingPlanCount(Optional.ofNullable(it.getM3RollingPlanCount()).orElse(0));
                    salesPlanLineSDO.setGmtModified(new Date());
                    //到岸折前金额
                    long outboundPrice = Objects.nonNull(it.getOutboundPrice()) ? it.getOutboundPrice() : 0;
                    long beforeMonthOutboundMoney = Optional.ofNullable(departmentMonthCount).orElse(0) * outboundPrice;
                    salesPlanLineSDO.setBeforeMonthOutboundMoney(beforeMonthOutboundMoney);
                    //到岸折后金额 到岸折后金额=到岸折前金额*(1-预估价格折扣率)
                    salesPlanLineSDO.calculateMonthOutboundMoney(salesPlanSDO.getEstimateDiscount());
                    //总量与三旬分配完后进行落库
                    SalesPlanLineEntity salesPlanLineEntity = SalesPlanLineEntity.of(salesPlanLineSDO);
                    Integer count = salesPlanLineEntity.doEdit();
                    if (count < 1) {
                        throw new FacadeException("OTS-02-006-00-16-009");
                    }
                    //}
                }
            }
        }
        //更新成功后  进行汇总更新
        PlanStatServiceResponse planStatServiceResponse = salesPlanService.planStatService(PlanStatServiceRequest.builder().planId(departmentResponse.getPlanId()).build());
        if (!planStatServiceResponse.getSuccess()) {
            throw new FacadeException("OTS-02-006-00-16-010");
        }
        return Result.success(true);
    }
}
